package com.mzj.saas.mservice.contract.service;

import com.mzj.saas.commons.DateUtils;
import com.mzj.saas.commons.ResultBean;
import com.mzj.saas.commons.enums.*;
import com.mzj.saas.commons.util.ConvertUtils;
import com.mzj.saas.commons.util.JsonUtils;
import com.mzj.saas.commons.vo.redis.TokenRedisVo;
import com.mzj.saas.config.oss.OssConfig;
import com.mzj.saas.config.sms.SmsConfig;
import com.mzj.saas.mservice.area.entity.Area;
import com.mzj.saas.mservice.area.repository.AreaRepository;
import com.mzj.saas.mservice.backlog.entity.BacklogItem;
import com.mzj.saas.mservice.backlog.entity.BacklogItemContractBill;
import com.mzj.saas.mservice.backlog.entity.BacklogItemContractConfirm;
import com.mzj.saas.mservice.backlog.repository.BacklogItemContractBillRepository;
import com.mzj.saas.mservice.backlog.repository.BacklogItemContractConfirmRepository;
import com.mzj.saas.mservice.backlog.repository.BacklogItemRepository;
import com.mzj.saas.mservice.bill.entity.HouseContractPayTime;
import com.mzj.saas.mservice.bill.entity.RentBill;
import com.mzj.saas.mservice.bill.entity.RentBillRelation;
import com.mzj.saas.mservice.bill.repository.HouseContractPayTimeRepository;
import com.mzj.saas.mservice.bill.repository.RentBillRelationRepository;
import com.mzj.saas.mservice.bill.repository.RentBillRepository;
import com.mzj.saas.mservice.code.vo.BusinessCodeVO;
import com.mzj.saas.mservice.community.entity.Community;
import com.mzj.saas.mservice.community.entity.CommunityBuild;
import com.mzj.saas.mservice.community.entity.CommunityBuildUnit;
import com.mzj.saas.mservice.community.repository.CommunityBuildRepository;
import com.mzj.saas.mservice.community.repository.CommunityBuildUnitRepository;
import com.mzj.saas.mservice.community.repository.CommunityRepository;
import com.mzj.saas.mservice.contract.entity.Contract;
import com.mzj.saas.mservice.contract.entity.ContractTemplate;
import com.mzj.saas.mservice.contract.entity.HouseContractAttachment;
import com.mzj.saas.mservice.contract.entity.HouseContractField;
import com.mzj.saas.mservice.contract.mapper.ContractAppRowMapper;
import com.mzj.saas.mservice.contract.repository.ContractRepository;
import com.mzj.saas.mservice.contract.repository.ContractTemplateRepository;
import com.mzj.saas.mservice.contract.repository.HouseContractAttachmentRepository;
import com.mzj.saas.mservice.contract.repository.HouseContractFieldRepository;
import com.mzj.saas.mservice.contract.vo.*;
import com.mzj.saas.mservice.department.entity.Department;
import com.mzj.saas.mservice.department.repository.DepartmentRepository;
import com.mzj.saas.mservice.house.entity.House;
import com.mzj.saas.mservice.house.entity.HouseMatchUser;
import com.mzj.saas.mservice.house.repository.CohabitRepository;
import com.mzj.saas.mservice.house.repository.HouseMatchUserRepository;
import com.mzj.saas.mservice.house.repository.HouseRepository;
import com.mzj.saas.mservice.oss.service.OSSService;
import com.mzj.saas.mservice.qiyuesuo.service.QiYueSuoEmployeeService;
import com.mzj.saas.mservice.sms.service.SmsService;
import com.mzj.saas.mservice.sys.entity.AppUser;
import com.mzj.saas.mservice.sys.entity.User;
import com.mzj.saas.mservice.sys.repository.AppUserRepository;
import com.mzj.saas.mservice.sys.repository.UserRepository;
import com.mzj.saas.mservice.sys.service.AppUserService;
import com.mzj.saas.mservice.sys.utils.SqlUtils;
import com.mzj.saas.redis.RedisService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class ContractAppService {
    private static final Logger log = LoggerFactory.getLogger(ContractAppService.class);

    private static final String CONTRACT_COUNT = "SELECT COUNT(1) ";
    private static final String CONTRACT_COLUM = "SELECT h.id as houseId, c.type as contractType, h.`org_id` AS orgId,c.`contract_nubmer` AS contractNubmer,\n"
            + "h.province_id as provinceId,h.city_id as cityId,h.district_id as districtId,h.street_id as streetId,\n"
            + "h.`residence_community_id` AS residenceCommunityId,h.`building_num` AS buildingNum,h.`unit`,\n"
            + "h.`room_number` AS roomNumber,u.`match_user_id` AS matchUserId,c.`start_time` AS startTime,c.`ent_time` AS entTime,\n"
            + "c.`rent_unit_amount` AS rentUnitAmount,c.`rent_amount` AS rentAmount,\n"
            + "c.`pay_type` AS payType,c.`status`,c.short_url as shortUrl,c.contract_doc_url as contractDocUrl";
    private static final String CONTRACT_FROM_MONITOR = " FROM (SELECT * FROM saas_house h WHERE h.`match_status` = 2) h LEFT JOIN (SELECT * FROM saas_house_contract WHERE `status` <> 0) c ON h.`id` = c.`house_id` \n"
            + "LEFT JOIN (SELECT * FROM saas_house_match_user WHERE STATUS = 1) u ON h.id = u.`house_id`";

    private static final String CONTRACT_FROM_MONITOR_MORE = " FROM (SELECT * FROM saas_house_match_user WHERE STATUS = 1) u "
            + "LEFT JOIN (SELECT * FROM saas_house_contract WHERE `status` <> 0) c ON u.match_user_id = c.match_user_id "
            + "LEFT JOIN (SELECT * FROM saas_house h WHERE h.`match_status` = 2) h ON h.id = u.`house_id`";

    private static final String ORDER_ORDER = " ORDER BY c.operation_time DESC";
    private static final String SQL_PAGE = " LIMIT ? OFFSET ?";

    @Autowired
    private RedisService redisService;
    @Autowired
    private JdbcTemplate jdbcTemplate;
    @Autowired
    private AppUserService appUserService;
    @Autowired
    private CommunityRepository communityRepository;
    @Autowired
    private CommunityBuildRepository communityBuildRepository;
    @Autowired
    private CommunityBuildUnitRepository communityBuildUnitRepository;
    @Autowired
    private AppUserRepository appUserRepository;
    @Autowired
    private ContractTemplateRepository contractTemplateRepository;
    @Autowired
    private ContractRepository contractRepository;
    @Autowired
    private HouseContractFieldRepository houseContractFieldRepository;
    @Autowired
    private HouseContractAttachmentRepository houseContractAttachmentRepository;
    @Autowired
    private OSSService ossService;
    @Autowired
    private OssConfig ossConfig;
    @Autowired
    @Qualifier("stringRedisTemplate")
    private StringRedisTemplate redisTemplate;
    @Autowired
    private HouseMatchUserRepository houseMatchUserRepository;
    @Autowired
    private HouseRepository houseRepository;
    @Autowired
    private DepartmentRepository departmentRepository;
    @Autowired
    private AreaRepository areaRepository;
    @Autowired
    private RentBillRepository rentBillRepository;
    @Autowired
    private RentBillRelationRepository rentBillRelationRepository;
    @Autowired
    private HouseContractPayTimeRepository houseContractPayTimeRepository;
    @Autowired
    private QiYueSuoEmployeeService qiYueSuoEmployeeService;
    @Autowired
    private BacklogItemRepository backlogItemRepository;
    @Autowired
    private BacklogItemContractBillRepository backlogItemContractBillRepository;
    @Autowired
    private BacklogItemContractConfirmRepository backlogItemContractConfirmRepository;
    @Autowired
    private SmsService smsService;
    @Autowired
    private SmsConfig smsConfig;
    @Autowired
    private UserRepository userRepository;
    @Autowired
    private CohabitRepository cohabitRepository;

    /**
     * 合同列表，实现合同列表的展示功能
     *
     * @param accessToken 权限鉴定
     * @param status      合同状态：0初稿 1待签约、2已签约待确认、3已确认待交租、4已交租待备案、5已备案履约中、6已到期待续约 7已续约
     * @param pageNumber  当前页
     * @param pageSize    每页条数
     * @return
     */
    public ResultBean<ContractApiData<ContractListVO>> contractList(String accessToken, Integer status,
                                                                    Integer pageNumber, Integer pageSize) {
        //设置模块返回成功
        ResultBean<ContractApiData<ContractListVO>> resultBean = new ResultBean<>();
        resultBean.setCode("10000");
        resultBean.setMsg("10000");
        ContractApiData<ContractListVO> apiData = new ContractApiData<>();
        resultBean.setResultData(apiData);
        try {
            //判断合同状态是否为空
            if (status == null) {
                return ResultBean.failedResultWithMsg("状态id为空");
            }
            //获取用户登录权限
            TokenRedisVo tokenRedisVo = redisService.findTokenVo(accessToken);
            //用户权限的鉴定
            if (tokenRedisVo == null) {
                return ResultBean.failedResultOfToken();
            }
            //获取用户ID
            String userId = tokenRedisVo.getId();
            //获取企业ID
            Long enterpriseId = tokenRedisVo.getEnterpriseId();
            //获取登录状态
            Integer loginType = tokenRedisVo.getLoginType();

            StringBuilder userSql = new StringBuilder();
            StringBuilder where = new StringBuilder();
            List<Object> userArgs = new ArrayList<>();
            List<Object> args = new ArrayList<>();
            //判断是企业登录还是个人登录
            if (loginType == 1) {// 企业登录
                // 1、查已绑定自己所属产权单位的所有公租房合同
                List<House> houses = houseRepository.findByOrgId(enterpriseId);
                List<String> houseIds = houses.stream().map(House::getId).distinct().collect(Collectors.toList());
                userSql.append(" and (h.id in ");

                if (houseIds != null && !houseIds.isEmpty()) {
                    userSql.append(SqlUtils.foreachIn(houseIds.size()));
                    userArgs.addAll(houseIds);
                    args.addAll(houseIds);
                } else {
                    userSql.append("(?)");
                    userArgs.add(null);
                    args.add(null);
                }
                // 2、查承租人是自己的
                userSql.append(" or u.match_user_id = ? )");
                userArgs.add(userId);
                args.add(userId);
            } else {// 个人登录
                //查承租人是自己的
                userSql.append(" and u.match_user_id = ?");
                userArgs.add(userId);
                args.add(userId);
            }

            if (status == 1) {// 待生成
                where.append(" and c.contract_nubmer is null");
            } else if (status == 2) {// 待签约
                where.append(" and c.status = ?");
                args.add(1);
            } else if (status == 3) {// 待交租
                where.append(" and c.status = ?");
                args.add(3);
            } else if (status == 4) {// 待续约
                where.append(" and c.status = ?");
                args.add(6);
            }
            // 总记录数
            Long total = jdbcTemplate.queryForObject(CONTRACT_COUNT + CONTRACT_FROM_MONITOR_MORE + " where 1 = 1" + userSql,
                    userArgs.toArray(), Long.class);
            if (total == 0) {
                return resultBean;
            }
            // 待生成总数
            Long yetCreateTotal = jdbcTemplate.queryForObject(
                    CONTRACT_COUNT + CONTRACT_FROM_MONITOR_MORE + " where c.contract_nubmer is null" + userSql,
                    userArgs.toArray(), Long.class);
            // 待签约总数
            Long yetSignTotal = jdbcTemplate.queryForObject(
                    CONTRACT_COUNT + CONTRACT_FROM_MONITOR_MORE + " where c.status = 1" + userSql, userArgs.toArray(),
                    Long.class);
            // 待交租总数
            Long yetPayTotal = jdbcTemplate.queryForObject(
                    CONTRACT_COUNT + CONTRACT_FROM_MONITOR_MORE + " where c.status = 3" + userSql, userArgs.toArray(),
                    Long.class);
            // 待续约总数
            Long yetRenewalTotal = jdbcTemplate.queryForObject(
                    CONTRACT_COUNT + CONTRACT_FROM_MONITOR_MORE + " where c.status = 6" + userSql, userArgs.toArray(),
                    Long.class);
            //设置当前页面
            args.add(pageSize);
            //设置每页条数
            args.add(pageNumber * pageSize);
            //查询数据
            List<ContractListVO> contractList = jdbcTemplate.query(
                    CONTRACT_COLUM + CONTRACT_FROM_MONITOR_MORE + " where 1 = 1" + userSql + where + ORDER_ORDER + SQL_PAGE,
                    new ContractAppRowMapper(), args.toArray());

            for (ContractListVO vo : contractList) {
                // 产权人标识
                if (vo.getOrgId().equals(enterpriseId)) {
                    vo.setOrgFlag(1);
                } else {
                    vo.setOrgFlag(0);
                }
                // 承租人标识
                if (userId.equals(vo.getMatchUserId() == null ? "" : vo.getMatchUserId())) {
                    vo.setMatchUserFlag(1);
                } else {
                    vo.setMatchUserFlag(0);
                }
            }

            // 查询小区名称
            List<String> residenceCommunityIds = contractList.stream()
                    .filter(vo -> vo.getResidenceCommunityId() != null).map(ContractListVO::getResidenceCommunityId)
                    .distinct().collect(Collectors.toList());
            if (!residenceCommunityIds.isEmpty()) {
                Map<String, String> map = communityRepository.findByIdIn(residenceCommunityIds).stream()
                        .collect(Collectors.toMap(Community::getId, Community::getName));
                if (!map.isEmpty()) {
                    contractList.forEach(vo -> vo.setResidenceCommunityName(map.get(vo.getResidenceCommunityId())));
                }
            }
            // 查询楼栋名称
            List<Long> buildingIds = contractList.stream().filter(vo -> vo.getBuildingNum() != null)
                    .map(ContractListVO::getBuildingNum).distinct().collect(Collectors.toList());
            if (!buildingIds.isEmpty()) {
                Map<Long, String> map = communityBuildRepository.findByIdIn(buildingIds).stream()
                        .collect(Collectors.toMap(CommunityBuild::getId, CommunityBuild::getName));
                if (!map.isEmpty()) {
                    contractList.forEach(vo -> vo.setBuildingNumName(map.get(vo.getBuildingNum())));
                }
            }
            // 查询单元名称
            List<Long> unitIds = contractList.stream().filter(vo -> vo.getUnit() != null).map(ContractListVO::getUnit)
                    .distinct().collect(Collectors.toList());
            if (!unitIds.isEmpty()) {
                Map<Long, String> map = communityBuildUnitRepository.findByIdIn(unitIds).stream()
                        .collect(Collectors.toMap(CommunityBuildUnit::getId, CommunityBuildUnit::getName));
                if (!map.isEmpty()) {
                    contractList.forEach(vo -> vo.setUnitName(map.get(vo.getUnit())));
                }
            }
            // 查询承租人名称
            List<String> ids = contractList.stream().filter(vo -> vo.getMatchUserId() != null).map(ContractListVO::getMatchUserId).distinct().collect(Collectors.toList());
            if (!ids.isEmpty()) {
                List<AppUser> appUsers = appUserRepository.findByIdOrEnterpriseIn(ids, ids);
                for (AppUser appUser : appUsers) {
                    for (ContractListVO vo : contractList) {
                        if (vo.getMatchUserId() != null) {
                            if (vo.getMatchUserId().equals(appUser.getId()) || vo.getMatchUserId().equals(appUser.getEnterpriseUserId())) {
                                vo.setMatchUserName(appUser.getName());
                            }
                        }
                    }
                }
            }
            //把对应的数据设置保存
            apiData.setData(contractList);
            apiData.setTotal(total);
            apiData.setYetCreateTotal(yetCreateTotal);
            apiData.setYetSignTotal(yetSignTotal);
            apiData.setYetPayTotal(yetPayTotal);
            apiData.setYetRenewalTotal(yetRenewalTotal);
            resultBean.setResultData(apiData);
        } catch (Exception e) {
            //记录报错日志
            log.error("ContractAppService contractList Exception = {}" + e.getMessage(), e);
            resultBean.setCode("10001");
            resultBean.setMsg("10001");
        }
        //把数据返回给前端页面
        resultBean.setResultData(apiData);
        return resultBean;
    }
    /**
     * 合同模板列表
     *
     * @return
     */
    public ResultBean<List<Map<String, Object>>> contractTemplate(String accessToken) {
        try {
            //获取用户登录权限
            TokenRedisVo tokenRedisVo = redisService.findTokenVo(accessToken);
            //用户权限的鉴定
            if (tokenRedisVo == null) {
                return ResultBean.failedResultOfToken();
            }
            //获取企业ID
            Long enterpriseId = tokenRedisVo.getEnterpriseId();
            //根据企业ID和操作状态：1正常 2已删除查询合同模板表
            List<ContractTemplate> contractTemplates = contractTemplateRepository.findByOrgIdAndStatusAndOperatorStatus(enterpriseId, 1, 1);
            List<Map<String, Object>> list = new ArrayList<>();
            //遍历存储数据
            for (ContractTemplate contractTemplate : contractTemplates) {
                Map<String, Object> map = new HashMap<>();
                map.put("contractTemplateNumber", contractTemplate.getContractTemplateNumber());
                map.put("name", contractTemplate.getName());
                list.add(map);
            }
            //把数据返回给前端页面
            return ResultBean.successfulResult(list);
        } catch (Exception e) {
            //记录报错日志
            log.error(e.getMessage(), e);
            return ResultBean.failedResultOfException();
        }
    }
    /**
     * 合同模板字段-生成合同
     *
     * @param contractTemplateNumber 合同模板序号
     * @return
     */
    public ResultBean<List<Map<String, Object>>> contractTemplateField(String accessToken, String contractTemplateNumber, String houseId, String matchUserId) {
        try {
            //记录操作日志
            log.info("contractTemplateField, contractTemplateNumber={}, houseId={}, matchUserId={}", contractTemplateNumber, houseId, matchUserId);
            //获取用户登录权限
            TokenRedisVo tokenRedisVo = redisService.findTokenVo(accessToken);
            //用户权限的鉴定
            if (tokenRedisVo == null) {
                return ResultBean.failedResultOfToken();
            }
            //获取用户ID
            String userId = tokenRedisVo.getId();
            //通过用户ID查询用户信息
            AppUser appUser = appUserRepository.findByIdOrEnterpriseUserId(userId, userId);
            //判断用户是否注册
            if (appUser == null) {
            	log.info("contractTemplateField, user not found, userId={}", userId);
                return ResultBean.failedResultWithMsg("登录用户未注册APP账户");
            }
            //判断合同模板序号是否为空
            if (StringUtils.isBlank(contractTemplateNumber)) {
                return ResultBean.failedResultOfParamWithMsg("合同模板序号为空");
            }
            //判断公租房id是否为空
            if (StringUtils.isBlank(houseId)) {
                return ResultBean.failedResultOfParamWithMsg("公租房id为空");
            }

            Map<String, Object> houseMap = new HashMap<>();
            //根据用户ID查询用户公租房信息
            Optional<House> optional = houseRepository.findById(houseId);
            //判断公租房是否存在
            if (!optional.isPresent()) {
                return ResultBean.failedResultWithMsg("公租房不存在");
            }
            //获取公租房属性
            House house = optional.get();

            // 查询房屋配租用户数据
            List<HouseMatchUser> houseMatchUsers = houseMatchUserRepository.findHouseIdAndStatus(houseId, 1);
            if (houseMatchUsers.isEmpty()) {
                return ResultBean.failedResultWithMsg("配租记录不存在");
            }

            AppUser user = null;
            // 单承租人模式
            if (house.getMatchType() == 1) {
                if (houseMatchUsers.size() > 1) {
                    return ResultBean.failedResultWithMsg("配租人数据错误");
                }
                user = appUserRepository.findByIdOrEnterpriseUserId(houseMatchUsers.get(0).getMatchUserId(), houseMatchUsers.get(0).getMatchUserId());
                if (user == null) {
                	log.info("contractTemplateField, AppUser not found, matchUserId={}", houseMatchUsers.get(0).getMatchUserId());
                    return ResultBean.failedResultWithMsg("房屋配租APP用户未注册");
                }
            } else {
                if (matchUserId != null) {
                    user = appUserRepository.findByIdOrEnterpriseUserId(matchUserId, matchUserId);
                    if (user == null) {
                    	log.info("contractTemplateField, matchUser not found, matchUserId={}", matchUserId);
                        return ResultBean.failedResultWithMsg("承租人APP用户未注册");
                    }
                }
            }

            // 房屋地址
            List<Long> ids = new ArrayList<>();
            ids.add(house.getProvinceId());
            ids.add(house.getCityId());
            ids.add(house.getDistrictId());
            List<Area> areas = areaRepository.findByIdIn(ids);
            StringBuilder address = new StringBuilder();
            for (Area area : areas) {
                address.append(area.getName());
            }

            Optional<Community> communityOptional = communityRepository.findById(house.getResidenceCommunityId());
            if (!communityOptional.isPresent()) {
                return ResultBean.failedResultWithMsg("小区不存在");
            }
            address.append(communityOptional.get().getName());

            Optional<CommunityBuild> buildOptional = communityBuildRepository.findById(house.getBuildingNum());
            if (!buildOptional.isPresent()) {
                return ResultBean.failedResultWithMsg("小区楼栋不存在");
            }
            address.append(buildOptional.get().getName() + "栋");

            Optional<CommunityBuildUnit> unitOptional = communityBuildUnitRepository.findById(house.getUnit());
            if (!unitOptional.isPresent()) {
                return ResultBean.failedResultWithMsg("小区单元不存在");
            }
            address.append(unitOptional.get().getName() + "单元");
            address.append(house.getRoomNumber() + "号");

            // 出租方
            Optional<Department> departmentOptional = departmentRepository.findById(house.getOrgId());
            if (!departmentOptional.isPresent()) {
                return ResultBean.failedResultWithMsg("公租房所属产权单位不存在");
            }
            Department department = departmentOptional.get();

            houseMap.put("lessorName", department.getName());
            houseMap.put("lessorMobile", appUser.getPhone());
            // 多承租人模式，无法确定当前使用哪一个承租人来签订合同，所以承租人信息不返回，页面手动填写，保存合同时在验证
            houseMap.put("leaseeName", user != null ? user.getName() : "");
            houseMap.put("leaseeMobile", user != null ? user.getPhone() : "");
            houseMap.put("cardNumber", user != null ? user.getCardNumber() : "");
            houseMap.put("housingArea", house.getArea());
            houseMap.put("address", address);
            houseMap.put("houseType", house.getRoom() + "室" + house.getHall() + "厅" + house.getToilet() + "卫");

            String sql = "SELECT a.default_id as fieldId,1 AS defaultField,a.must_status AS mustStatus,\n"
                    + "b.`field_name` AS fieldName, b.name,b.show_status as showStatus,null as value\n"
                    + "FROM `saas_contract_template_field` a JOIN `saas_contract_template_default_field` b ON a.default_id = b.id\n"
                    + "WHERE a.`contract_template_number` = ?";
            List<Map<String, Object>> list = jdbcTemplate.queryForList(sql, contractTemplateNumber);

            for (Map map : list) {
                String fieldName = String.valueOf(map.get("fieldName"));
                map.put("value", houseMap.get(fieldName));
            }

            // 合同自定义字段
            String sql2 = "SELECT f.id AS fieldId,0 AS defaultField,f.field_name AS fieldName,f.name,\n"
                    + "f.must_status AS mustStatus,f.show_status AS showStatus,null AS value\n"
                    + "FROM `saas_contract_template_custom_field` f WHERE f.contract_template_number = ?";
            List<Map<String, Object>> list2 = jdbcTemplate.queryForList(sql2, contractTemplateNumber);
            list.addAll(list2);

            return ResultBean.successfulResult(list);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return ResultBean.failedResultOfException();
        }
    }
    /**
     * 合同模板附件
     *
     * @param contractTemplateNumber 合同模板序号
     * @return
     */
    public ResultBean<List<Map<String, Object>>> contractTemplateAttachment(String contractTemplateNumber) {
        try {
            if (StringUtils.isBlank(contractTemplateNumber)) {
                return ResultBean.failedResultOfParamWithMsg("合同模板序号为空");
            }

            String sql = "SELECT a.attachment_id as attachmentId,a.type,b.name,b.unit,b.current_situation AS currentSituation,b.unit_price AS unitPrice\n"
                    + "FROM `saas_contract_template_custom_attachment` a JOIN `saas_contract_attachment` b ON a.`attachment_id` = b.id   \n"
                    + "WHERE a.`contract_template_number` = ? AND a.status = 1\n" + "UNION ALL\n"
                    + "SELECT a.attachment_id as attachmentId,a.type,a.name,a.unit,a.current_situation AS currentSituation,a.unit_price AS unitPrice\n"
                    + "FROM `saas_contract_template_custom_attachment` a \n"
                    + "WHERE a.`contract_template_number` = ? AND a.status = 1 AND a.type = 2";
            List<Map<String, Object>> list = jdbcTemplate.queryForList(sql, contractTemplateNumber,
                    contractTemplateNumber);

            return ResultBean.successfulResult(list);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return ResultBean.failedResultOfException();
        }
    }

    public ResultBean<Object> saveContract(String accessToken, ContractVO vo, String customField,
                                           String contractAttachment) {
        try {
            TokenRedisVo tokenRedisVo = redisService.findTokenVo(accessToken);
            if (tokenRedisVo == null) {
                return ResultBean.failedResultOfToken();
            }
            String userId = tokenRedisVo.getId();

            String userName = "";
            AppUser user = appUserService.findByIdAndStatus(userId, 1, tokenRedisVo.getLoginType());
            if (user != null) {
                userName = user.getName();
            } else {
                User epUser = userRepository.findUserById(userId);
                if (epUser == null) {
                    log.info("ContractAppService saveContract ----> 用户不存在, operatorId = {}", userId);
                    return ResultBean.failedResultWithMsg("用户不存在");
                }
                userName = epUser.getName();
            }

            // 参数验证
            if (vo == null) {
                return ResultBean.failedResultOfParamWithMsg("参数为空");
            }

            /*// 保存前，删除之前草稿状态合同
            Contract draft = contractRepository.findByHouseIdAndStatus(vo.getHouseId(), 0);
            if (draft != null) {
                String no = draft.getContractNubmer();
                contractRepository.delete(draft);
                houseContractFieldRepository.deleteByContractNubmer(no);
                houseContractAttachmentRepository.deleteByContractNubmer(no);
            }*/

            // 合同
            Contract contract = new Contract();
            //redisTemplate.opsForValue().increment("CONTRACT_NUMBER", 1);
            //Object number = redisTemplate.opsForValue().get("CONTRACT_NUMBER");
            Long number = redisService.incr("CONTRACT_NUMBER", 24);
            int len = 6 - number.toString().length();
            StringBuilder builder = new StringBuilder();
            for (int i = 0; i < len; i++) {
                builder.append("0");
            }
            contract.setContractNubmer(
                    "HT" + DateUtils.format(new Date(), DateUtils.FORMAT_8) + builder.toString() + number);

            contract.setContractTemplateNumber(vo.getContractTemplateNumber());
            contract.setHouseId(vo.getHouseId());
            contract.setLessorName(vo.getLessorName());
            contract.setLessorUserName(userName);
            contract.setLessorMobile(vo.getLessorMobile());

            // 多承租人模式下，承租人为空，此时需要验证合同填写的承租人用户是否存在
            if (vo.getMatchUserId() == null) {
                AppUser appUser = appUserRepository.findByCardNumber(vo.getCardNumber(), UserLoginTypeEnum.CONSUMER.getValue());
                if (appUser == null) {
                    return ResultBean.failedResultOfParamWithMsg("承租人未找到");
                }
                if (appUser.getName().equals(vo.getLeaseeName())) {
                    return ResultBean.failedResultOfParamWithMsg("承租人姓名与认证信息不匹配");
                }

                if (appUser.getPhone().equals(vo.getLeaseeMobile())) {
                    return ResultBean.failedResultOfParamWithMsg("承租人手机号码与认证信息不匹配");
                }

                if (appUser.getCardNumber().equals(vo.getCardNumber())) {
                    return ResultBean.failedResultOfParamWithMsg("承租人身份证号码与认证信息不匹配");
                }
                // 多承租人模式，验证当前填写的承租人信息是否为当前房屋承租人
                HouseMatchUser matchUser = houseMatchUserRepository.findByMatchUserIdOrMatchUserIdAndStatus(appUser.getId(), appUser.getEnterpriseUserId(), contract.getHouseId(), 1);
                if (matchUser == null) {
                    return ResultBean.failedResultOfParamWithMsg("承租人未找到");
                }
                contract.setMatchUserId(matchUser.getMatchUserId());
            } else {
                contract.setMatchUserId(vo.getMatchUserId());
            }

            contract.setLeaseeName(vo.getLeaseeName());
            contract.setLeaseeMobile(vo.getLeaseeMobile());
            contract.setCardNumber(vo.getCardNumber());

            contract.setStartTime(DateUtils.convert(vo.getStartTime(), DateUtils.FORMAT_DATE_8));
            contract.setEntTime(DateUtils.convert(vo.getEntTime(), DateUtils.FORMAT_DATE_8));
            contract.setHousingArea(vo.getHousingArea());
            contract.setRentUnitAmount(ConvertUtils.yuan2fen(vo.getRentUnitAmount()));// 元转分
            contract.setRentAmount(ConvertUtils.yuan2fen(vo.getRentAmount()));// 元转分
            contract.setPayType(vo.getPayType());
            contract.setEarnestMoney(ConvertUtils.yuan2fen(vo.getEarnestMoney()));// 元转分
            contract.setProvinceId(vo.getProvinceId());
            contract.setCityId(vo.getCityId());
            contract.setDistrictId(vo.getDistrictId());
            contract.setStreetId(vo.getStreetId());
            contract.setAddress(vo.getAddress());
            contract.setRoom(vo.getRoom());
            contract.setHall(vo.getHall());
            contract.setToilet(vo.getToilet());
            contract.setStatus(0);// 初稿
            contract.setReminderTime(DateUtils.convert(
                    DateUtils.getAddDaysTime(vo.getEntTime(), DateUtils.FORMAT_DATE_8, -30), DateUtils.FORMAT_DATE_8));// 到期提醒时间，默认提前一个月
            contract.setOperationId(tokenRedisVo.getId());
            contract.setOperationTime(new Date());
            Contract save = contractRepository.save(contract);

            // 自定义字段
            if (!StringUtils.isBlank(customField)) {
                List<Map<String, Object>> fields = JsonUtils.str2obj(customField, List.class);
                for (Map map : fields) {
                    HouseContractField field = new HouseContractField();
                    field.setContractNubmer(save.getContractNubmer());
                    Object fieldId = map.get("fieldId");
                    field.setFieldId(Long.valueOf(String.valueOf(fieldId)));
                    Object fieldName = map.get("fieldName");
                    field.setFieldName(String.valueOf(fieldName));
                    Object name = map.get("name");
                    field.setName(String.valueOf(name));
                    Object value = map.get("value");
                    field.setValue(String.valueOf(value));
                    houseContractFieldRepository.save(field);
                }
            }
            // 合同附件
            if (!StringUtils.isBlank(contractAttachment)) {
                List<Map<String, Object>> attachments = JsonUtils.str2obj(contractAttachment, List.class);
                for (Map map : attachments) {
                    HouseContractAttachment attachment = new HouseContractAttachment();
                    attachment.setContractNubmer(save.getContractNubmer());
                    Integer type = Integer.valueOf(String.valueOf(map.get("type")));
                    attachment.setType(type);
                    if (type == 1) {
                        Object attachmentId = map.get("attachmentId");
                        attachment.setAttachmentId(Long.valueOf(String.valueOf(attachmentId)));
                    }
                    Object name = map.get("name");
                    attachment.setName(String.valueOf(name));
                    Object unit = map.get("unit");
                    attachment.setUnit(String.valueOf(unit));
                    Object currentSituation = map.get("currentSituation");
                    attachment.setCurrentSituation(String.valueOf(currentSituation));
                    Object unitPrice = map.get("unitPrice");
                    attachment.setUnitPrice(String.valueOf(unitPrice));
                    attachment.setOperatorId(userId);
                    attachment.setLastUpdateTime(new Date());
                    houseContractAttachmentRepository.save(attachment);
                }
            }

            qiYueSuoEmployeeService.validateAddEmployeeExists(save.getLessorName(), save.getLessorMobile(), save.getLessorUserName());

            return ResultBean.successfulResult(save.getContractNubmer());
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return ResultBean.failedResultOfException();
        }
    }

    public ResultBean<Object> findTemplate(String contractNubmer) {
        try {
            if (StringUtils.isBlank(contractNubmer)) {
                return ResultBean.failedResultOfParamWithMsg("合同编号为空");
            }

            Optional<Contract> optional = contractRepository.findById(contractNubmer);
            if (!optional.isPresent()) {
                return ResultBean.failedResultWithMsg("合同不存在");
            }
            Contract contract = optional.get();
            String contractTemplateNumber = contract.getContractTemplateNumber();
            ContractTemplate contractTemplate = contractTemplateRepository
                    .findByContractTemplateNumber(contractTemplateNumber);
            if (contractTemplate == null) {
                return ResultBean.failedResultWithMsg("合同模板不存在");
            }
            String name = contractTemplate.getName();

            return ResultBean.successfulResult(name);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return ResultBean.failedResultOfException();
        }
    }

    public ResultBean<Object> findContractField(String contractNubmer) {
        try {
            if (StringUtils.isBlank(contractNubmer)) {
                return ResultBean.failedResultOfParamWithMsg("合同编号为空");
            }

            Optional<Contract> optional = contractRepository.findById(contractNubmer);
            if (!optional.isPresent()) {
                return ResultBean.failedResultOfParamWithMsg("合同不存在");
            }
            Contract contract = optional.get();
            String contractTemplateNumber = contract.getContractTemplateNumber();

            Map<String, Object> contractMap = new HashMap<>();
            contractMap.put("lessorName", contract.getLessorName());
            contractMap.put("lessorMobile", contract.getLessorMobile());
            contractMap.put("leaseeName", contract.getLeaseeName());
            contractMap.put("leaseeMobile", contract.getLeaseeMobile());
            contractMap.put("cardNumber", contract.getCardNumber());
            contractMap.put("startTime", contract.getStartTime());
            contractMap.put("entTime", contract.getEntTime());
            contractMap.put("housingArea", contract.getHousingArea());
            contractMap.put("rentUnitAmount", ConvertUtils.fen2yuan(contract.getRentUnitAmount()));// 分转元
            contractMap.put("rentAmount", ConvertUtils.fen2yuan(contract.getRentAmount()));// 分转元
            contractMap.put("payType", contract.getPayType());
            contractMap.put("earnestMoney", ConvertUtils.fen2yuan(contract.getEarnestMoney()));// 分转元
            contractMap.put("address", contract.getAddress());
            contractMap.put("room", contract.getRoom());
            contractMap.put("hall", contract.getHall());
            contractMap.put("toilet", contract.getToilet());
            // 合同默认字段
            String sql = "SELECT b.`field_name` AS fieldName, b.name,null as value\n"
                    + "FROM `saas_contract_template_field` a JOIN `saas_contract_template_default_field` b ON a.default_id = b.id\n"
                    + "WHERE a.`contract_template_number` = ?";
            List<Map<String, Object>> list = jdbcTemplate.queryForList(sql, contractTemplateNumber);

            for (Map map : list) {
                String fieldName = String.valueOf(map.get("fieldName"));
                map.put("value", contractMap.get(fieldName));
                if (fieldName.equals("rentDeadline")) {
                    String s = String.valueOf(contractMap.get("startTime"));
                    String e = String.valueOf(contractMap.get("entTime"));
                    String startTime = DateUtils.format(DateUtils.convert(s, DateUtils.FORMAT_DATE_8),
                            DateUtils.FORMAT_DATE_8);
                    String entTime = DateUtils.format(DateUtils.convert(e, DateUtils.FORMAT_DATE_8),
                            DateUtils.FORMAT_DATE_8);
                    map.put("value", startTime + " 至 " + entTime);
                }

                if (fieldName.equals("houseType")) {
                    String room = String.valueOf(contractMap.get("room"));
                    String hall = String.valueOf(contractMap.get("hall"));
                    String toilet = String.valueOf(contractMap.get("toilet"));
                    map.put("value", room + "室" + hall + "厅" + toilet + "卫");
                }
            }
            // 合同自定义字段
            String sql2 = "SELECT f.field_name AS fieldName,f.name,f.value\n"
                    + "FROM `saas_house_contract_field` f WHERE f.contract_nubmer = ?";
            List<Map<String, Object>> list2 = jdbcTemplate.queryForList(sql2, contractNubmer);
            list.addAll(list2);

            return ResultBean.successfulResult(list);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return ResultBean.failedResultOfException();
        }
    }

    public ResultBean<Object> findContractAttachment(String contractNubmer) {
        try {
            if (StringUtils.isBlank(contractNubmer)) {
                return ResultBean.failedResultOfParamWithMsg("合同编号为空");
            }

            String sql = "SELECT a.name,a.unit,a.current_situation AS currentSituation,a.unit_price AS unitPrice\n"
                    + "FROM `saas_house_contract_attachment` a WHERE a.contract_nubmer = ?";
            List<Map<String, Object>> list = jdbcTemplate.queryForList(sql, contractNubmer);

            return ResultBean.successfulResult(list);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return ResultBean.failedResultOfException();
        }
    }

    public ResultBean<String> templateContent(String contractNubmer) {
        try {
            if (StringUtils.isBlank(contractNubmer)) {
                return ResultBean.failedResultOfParamWithMsg("合同编号为空");
            }

            Optional<Contract> optional = contractRepository.findById(contractNubmer);
            if (!optional.isPresent()) {
                return ResultBean.failedResultOfParamWithMsg("合同不存在");
            }
            Contract contract = optional.get();
            String contractTemplateNumber = contract.getContractTemplateNumber();
            ContractTemplate contractTemplate = contractTemplateRepository
                    .findByContractTemplateNumber(contractTemplateNumber);
            if (contractTemplate == null) {
                return ResultBean.failedResultWithMsg("合同模板不存在");
            }
            String content = contractTemplate.getContent();

            return ResultBean.successfulResult(content);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return ResultBean.failedResultOfException();
        }
    }
    /**
     * 生成合同按钮
     *
     * @param contractNubmer 合同编号
     * @return
     */
    public ResultBean<Object> createButton(String contractNubmer, String signingFileUrl) {
        try {
            //判断合同是否为空
            if (StringUtils.isBlank(contractNubmer)) {
                return ResultBean.failedResultOfParamWithMsg("合同编号为空");
            }
            //判断签字文件是否
            if (StringUtils.isBlank(signingFileUrl)) {
                return ResultBean.failedResultOfParamWithMsg("签字文件路径为空");
            }
            //根据 签约编号:自动生成，长度固定8位，查询合同数据
            Optional<Contract> optional = contractRepository.findById(contractNubmer);
            if (!optional.isPresent()) {
                return ResultBean.failedResultOfParamWithMsg("合同不存在");
            }
            //存储合同数据
            Contract contract = optional.get();
            contract.setStatus(1);// 待签约
            contract.setSigningFileUrl(signingFileUrl);
            contract.setOperationTime(new Date());
            contractRepository.save(contract);
            //把数据返回给前端页面
            return ResultBean.successfulResult(null);
        } catch (Exception e) {
            //记录报错日志
            log.error(e.getMessage(), e);
            return ResultBean.failedResultOfException();
        }
    }
    /**
     * 甲方上传签字图片，，实现了手写签名图片的存储
     *
     * @param contractNubmer 合同编号
     * @param file 签字图片
     * @return
     */
    public ResultBean<Object> lessorUploadSign(String contractNubmer, MultipartFile file) {
        try {
            //判断合同是否为空
            if (StringUtils.isBlank(contractNubmer)) {
                return ResultBean.failedResultOfParamWithMsg("合同编号为空");
            }
            //判断是否有签字文件过来
            if (file == null) {
                return ResultBean.failedResultOfParamWithMsg("上传文件为空");
            }
            // 如果有缓存，先删除上传文件
            Object object = redisTemplate.opsForValue().get("lessorContract:fileKey:" + contractNubmer);
            if (object != null) {
                String fileKey = object.toString();
                ossService.deleteObject(ossConfig.getOssBucketName(), fileKey);
            }
            // 上传成功后，重新设置缓存
            ResultBean<Object> objectResultBean = ossService.putFile(ossConfig.getOssBucketName(), file,
                    OSSUploadFileTypeEnum.SIGN.toString());
            String fileKey = objectResultBean.getResultData().toString();
            //把合同编号和手写签名文件存储在redis中并设置过期时间为5分钟
            redisTemplate.opsForValue().set("lessorContract:fileKey:" + contractNubmer, fileKey, 5, TimeUnit.MINUTES);
            //把文件存储到oss服务器上
            String url = ossService.getOssFilePath(fileKey);
            //把数据返回给前端页面
            return ResultBean.successfulResult(url);
        } catch (Exception e) {
            //记录报错日志
            log.error(e.getMessage(), e);
            return ResultBean.failedResultOfException();
        }
    }
    /**
     * 乙方上传签字图片，，实现了手写签名图片的存储
     *
     * @param contractNubmer 合同编号
     * @param file 签字图片
     * @return
     */
    public ResultBean<Object> leaseeUploadSign(String contractNubmer, MultipartFile file) {
        try {
            //判断合同是否为空
            if (StringUtils.isBlank(contractNubmer)) {
                return ResultBean.failedResultOfParamWithMsg("合同编号为空");
            }
            //判断是否有签字文件过来
            if (file == null) {
                return ResultBean.failedResultOfParamWithMsg("上传文件为空");
            }
            // 如果有缓存，先删除上传文件
            Object object = redisTemplate.opsForValue().get("leaseeContract:fileKey:" + contractNubmer);
            if (object != null) {
                String fileKey = object.toString();
                ossService.deleteObject(ossConfig.getOssBucketName(), fileKey);
            }
            // 上传成功后，重新设置缓存
            ResultBean<Object> objectResultBean = ossService.putFile(ossConfig.getOssBucketName(), file,
                    OSSUploadFileTypeEnum.SIGN.toString());
            String fileKey = objectResultBean.getResultData().toString();
            //把合同编号和手写签名文件存储在redis中并设置过期时间为5分钟
            redisTemplate.opsForValue().set("leaseeContract:fileKey:" + contractNubmer, fileKey, 5, TimeUnit.MINUTES);
            //把文件存储到oss服务器上
            String url = ossService.getOssFilePath(fileKey);
            //把数据返回给前端页面
            return ResultBean.successfulResult(url);
        } catch (Exception e) {
            //记录报错日志
            log.error(e.getMessage(), e);
            return ResultBean.failedResultOfException();
        }
    }
    /**
     * 查看签字图片
     *
     * @param contractNubmer 合同编号
     * @return
     */
    public ResultBean<Map<String, Object>> findSignPic(String contractNubmer) {
        try {
            if (StringUtils.isBlank(contractNubmer)) {
                return ResultBean.failedResultOfParamWithMsg("合同编号为空");
            }

            Optional<Contract> optional = contractRepository.findById(contractNubmer);
            if (!optional.isPresent()) {
                return ResultBean.failedResultOfParamWithMsg("合同不存在");
            }
            Contract contract = optional.get();
            Map<String, Object> map = new HashMap<>();
            map.put("signingFileUrl", contract.getSigningFileUrl());
            map.put("contractFileUrl", contract.getContractFileUrl());

            Date contractTime = contract.getContractTime();
            map.put("contractTime",
                    contractTime == null ? "" : DateUtils.format(contractTime, DateUtils.FORMAT_DATETIME_14));

            return ResultBean.successfulResult(map);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return ResultBean.failedResultOfException();
        }
    }

    public ResultBean<Object> signConfirm(String contractNubmer, String contractFileUrl, String contractTime) {
        try {
            log.info("ContractAppService signConfirm, contractFileUrl={}, contractTime={}", contractFileUrl, contractTime);
            if (StringUtils.isBlank(contractNubmer)) {
                return ResultBean.failedResultOfParamWithMsg("合同编号为空");
            }
            if (StringUtils.isBlank(contractFileUrl)) {
                return ResultBean.failedResultOfParamWithMsg("签字文件路径为空");
            }
            if (StringUtils.isBlank(contractTime)) {
                return ResultBean.failedResultOfParamWithMsg("签约时间为空");
            }

            Optional<Contract> optional = contractRepository.findById(contractNubmer);
            if (!optional.isPresent()) {
                return ResultBean.failedResultOfParamWithMsg("合同不存在");
            }
            Contract contract = optional.get();

            Optional<House> houseOptional = houseRepository.findById(contract.getHouseId());
            if (!houseOptional.isPresent()) {
                return ResultBean.failedResultWithMsg("公租房不存在");
            }
            House house = houseOptional.get();

            contract.setStatus(2);// 已签约待确认
            contract.setContractFileUrl(contractFileUrl);
            contract.setContractTime(DateUtils.convert(contractTime, DateUtils.FORMAT_DATETIME_14));
            contractRepository.save(contract);

            // 公租房状态修改成 已出租
            house.setLeaseStatus(1);
            house.setContractNumber(contractNubmer);
            houseRepository.save(house);

            return ResultBean.successfulResult(null);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return ResultBean.failedResultOfException();
        }
    }

    public ResultBean<Object> setReminderTime(Integer type) {
        try {
            if (type == null) {
                return ResultBean.failedResultOfParamWithMsg("设置类型为空");
            }

            return ResultBean.successfulResult(null);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return ResultBean.failedResultOfException();
        }
    }

    public ResultBean<ContractDetailVO> contractDetail(String contractNubmer) {
        try {
            if (StringUtils.isBlank(contractNubmer)) {
                return ResultBean.failedResultOfParamWithMsg("合同编号为空");
            }
            Optional<Contract> optional = contractRepository.findById(contractNubmer);
            if (!optional.isPresent()) {
                return ResultBean.failedResultOfParamWithMsg("合同不存在");
            }
            Contract contract = optional.get();
            // 承租人
            //Optional<AppUser> appUserOptional = appUserRepository.findById(contract.getMatchUserId());
            AppUser appuser = appUserRepository.findByIdOrEnterpriseUserId(contract.getMatchUserId(), contract.getMatchUserId());
            if (appuser == null) {
                return ResultBean.failedResultWithMsg("用户不存在");
            }

            ContractDetailVO vo = new ContractDetailVO();
            vo.setMatchUserName(appuser.getName());
            vo.setAddress(contract.getAddress());
            vo.setRoom(contract.getRoom());
            vo.setHall(contract.getHall());
            vo.setToilet(contract.getToilet());
            vo.setHousingArea(contract.getHousingArea());
            vo.setRentAmount(ConvertUtils.fenConvertYuan(contract.getRentAmount()));
            vo.setEarnestMoney(ConvertUtils.fenConvertYuan(contract.getEarnestMoney()));
            vo.setStartTime(DateUtils.format(contract.getStartTime(), DateUtils.FORMAT_DATE_8));
            vo.setEntTime(DateUtils.format(contract.getEntTime(), DateUtils.FORMAT_DATE_8));
            vo.setPayType(contract.getPayType());
            vo.setWaterMeter(0);
            vo.setAmmeter(0);
            vo.setGasMeter(0);

            return ResultBean.successfulResult(vo);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return ResultBean.failedResultOfException();
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public ResultBean<Object> confirm(String accessToken, String contractNubmer, String filePath) {
        try {
            TokenRedisVo tokenRedisVo = redisService.findTokenVo(accessToken);
            if (tokenRedisVo == null) {
                return ResultBean.failedResultOfToken();
            }
            String userId = tokenRedisVo.getId();

            log.info("ContractAppService confirm, contractNubmer={}", contractNubmer);
            if (StringUtils.isBlank(contractNubmer)) {
                return ResultBean.failedResultOfParamWithMsg("合同编号为空");
            }

            Contract contract = contractRepository.findByContractNubmer(contractNubmer);
            if (contract == null) {
                return ResultBean.failedResultWithMsg("合同不存在");
            }

            // 如果有合同文件(线下签约)
            // 上传合同到oss
            if(StringUtils.isNotEmpty(filePath)){
            	/*ResultBean<Object> ossFilekey = ossService.putFile(ossConfig.getOssBucketName(), file, OSSUploadFileTypeEnum.CONTRACT.toString());
             	if(ossFilekey.getCode().equals(StatusCode.ERROR_CODE_10001.getErrorCode())){
             		log.error("确认合同, 合同上传失败, contractId={}", contract.getContractNubmer());
             		return ResultBean.failedResultWithMsg("合同上传失败");
             	}*/
             	contract.setContractDocUrl(filePath);
            }else{
            	log.info("确认操作, 无合同文件, contractNumber={}", contract.getContractNubmer());
            }

            String matchUserId = contract.getMatchUserId();

            String houseId = contract.getHouseId();
            Optional<House> houseOpt = houseRepository.findById(houseId);
            if (!houseOpt.isPresent()) {
                return ResultBean.failedResultWithMsg("公租房不存在");
            }
            House house = houseOpt.get();
            Long orgId = house.getOrgId();

            int status = contract.getStatus();
            if (status == ContractStatusEnum.WAITING_RENT.getValue()) {
                return ResultBean.failedResultWithMsg("合同已确认，不可重复确认");
            }

            Date date = new Date();
            // 产权单位设置应缴费日期
            HouseContractPayTime houseContractPayTime = houseContractPayTimeRepository.findByOrgId(orgId);
            Integer time = 10;
            if (houseContractPayTime != null) {
                time = houseContractPayTime.getTime();
            }

            // 生成租金账单
            RentBill bill = new RentBill();
            bill.setOrgId(orgId);
            bill.setHouseId(house.getId());
            bill.setCommunityId(house.getResidenceCommunityId());
            bill.setCreateTime(date);
            bill.setMatchUserId(contract.getMatchUserId());
            bill.setBuildingNum(house.getBuildingNum());
            bill.setRoomNumber(house.getRoomNumber());
            bill.setUnit(house.getUnit());
            bill.setAuditStatus(1);
            bill.setPaymentStatus(0);
            bill.setMeasureUnit("元/平方米/月");
            bill.setChargeType(ChargeTypeEnum.RENT.getValue());
            Integer cose = contract.getRentAmount() * 12;
            bill.setCost(cose);
            bill.setStartTime(contract.getStartTime());
            bill.setEndTime(contract.getEntTime());
            bill.setShouldPayTime(DateUtils.getAddDaysTime(contract.getStartTime(), time));
            bill.setType(1);
            RentBill billSave = rentBillRepository.save(bill);

            RentBillRelation relation = new RentBillRelation();
            relation.setContractNubmer(contract.getContractNubmer());
            relation.setHouseId(house.getId());
            relation.setMatchUserId(contract.getMatchUserId());
            relation.setRentBillId(bill.getId());
            rentBillRelationRepository.save(relation);

            // 生成押金账单
            RentBill bill2 = new RentBill();
            bill2.setHouseId(house.getId());
            bill2.setCommunityId(house.getResidenceCommunityId());
            bill2.setBuildingNum(house.getBuildingNum());
            bill2.setUnit(house.getUnit());
            bill2.setRoomNumber(house.getRoomNumber());
            bill2.setOrgId(orgId);
            bill2.setMatchUserId(contract.getMatchUserId());
            bill2.setChargeType(ChargeTypeEnum.DEPOSIT.getValue());
            bill2.setMeasureUnit("元");
            Integer earnestMoney = contract.getEarnestMoney();
            bill2.setCost(earnestMoney);
            bill2.setStartTime(contract.getStartTime());
            bill2.setEndTime(contract.getEntTime());
            bill2.setAuditStatus(1);
            bill2.setPaymentStatus(0);
            bill2.setShouldPayTime(DateUtils.getAddDaysTime(contract.getStartTime(), time));
            bill2.setCreateTime(date);
            bill2.setType(1);
            RentBill bill2Save = rentBillRepository.save(bill2);

            RentBillRelation relation2 = new RentBillRelation();
            relation2.setContractNubmer(contract.getContractNubmer());
            relation2.setHouseId(house.getId());
            relation2.setMatchUserId(contract.getMatchUserId());
            relation2.setRentBillId(bill2.getId());
            rentBillRelationRepository.save(relation2);

            // 修改合同状态
            contract.setStatus(ContractStatusEnum.WAITING_RENT.getValue());// 已确认待交租
            // 续约
            if (contract.getBusinessType() != null && contract.getBusinessType() == 2) {
                // 修改公租房续约状态
                house.setRenewalStatus(1);
                houseRepository.save(house);
            }
            contractRepository.save(contract);

            //修改公租房出租状态
            house.setLeaseStatus(HouseLeaseStatusEnum.LEASE.getValue());
            houseRepository.save(house);

            // 生成二维码缴费信息
            BusinessCodeVO vo = new BusinessCodeVO();
            vo.setAmount(bill.getCost() + bill2.getCost());
            vo.setContractNubmer(contract.getContractNubmer());
            vo.setOrderIds(Arrays.asList(bill.getId(), bill2.getId()));
            vo.setShortUrl(contract.getShortUrl());
            vo.setType(2);
            vo.setHouseIds(Arrays.asList(contract.getHouseId()));

            //更新合同确认待办事项状态
            BacklogItemContractConfirm confirm = backlogItemContractConfirmRepository.findByContractNubmer(contractNubmer);
            if (confirm != null) {
                Optional<BacklogItem> backlogItemOpt = backlogItemRepository.findById(confirm.getBacklogItemId());
                if (backlogItemOpt.isPresent()) {
                    BacklogItem item = backlogItemOpt.get();
                    item.setBusinessStatus("已确认");
                    item.setHandleStatus(1);
                    item.setHandlerTime(date);
                    backlogItemRepository.save(item);
                }
            }

            AppUser user = null;
            if (StringUtils.isNotBlank(matchUserId)){
                user = appUserRepository.findByIdOrEnterpriseUserId(matchUserId, matchUserId);

            }

            //生成租金/押金待办事项
            BacklogItem backlogItem = new BacklogItem();
            backlogItem.setHouseId(contract.getHouseId());
            //backlogItem.setOrgId(orgId);
            backlogItem.setType(BacklogItemTypeEnum.CONTRACT_BILL.getValue());
            backlogItem.setTitle("租金/押金账单待缴费");
            backlogItem.setContent("缴费描述：合同已生成，请尽快缴费");
            backlogItem.setBusinessStatus("待缴费");
            backlogItem.setHandleStatus(0);
            backlogItem.setOperatorId(userId);
            backlogItem.setMatchUserId(matchUserId);
            if (user != null ){
                backlogItem.setPhone(user.getPhone());
            }
            backlogItem.setCreateTime(date);
            BacklogItem save = backlogItemRepository.save(backlogItem);

            BacklogItemContractBill contractBill = new BacklogItemContractBill();
            contractBill.setBacklogItemId(save.getId());
            contractBill.setAmount(cose + earnestMoney);
            contractBill.setMatchUserId(matchUserId);
            contractBill.setRentBillId(billSave.getId());
            contractBill.setDepositBillId(bill2Save.getId());
            contractBill.setContractNumber(contractNubmer);
            backlogItemContractBillRepository.save(contractBill);

            //发送租金缴纳短信
            smsService.sendTemplateSms(contract.getLeaseeMobile(), smsConfig.getRentbillTemplateCode());

            //根据房屋ID和承租人ID，获得申请ID
//            List<HouseMatchUser> houseMatchUserList = houseMatchUserRepository.findByHouseIdAndMatchUserIdAndStatus(contract.getHouseId(), contract.getMatchUserId(), 1);
//            if (null != houseMatchUserList && houseMatchUserList.size()>0){
//                List<Long> applyIdList = houseMatchUserList.stream().map(x -> x.getApplyId()).collect(Collectors.toList());
//                List<Cohabit> cohabitList = cohabitRepository.findByApplyIdIn(applyIdList);
//
//                for (Cohabit cohabit : cohabitList) {
//                    if (StringUtils.isEmpty(cohabit.getMobile())){
//                        continue;
//                    }
//                    AppUser appUser = appUserRepository.findByPhone(cohabit.getMobile());
//
//                    //生成租金/押金待办事项
//                    BacklogItem backlogItems = new BacklogItem();
//                    backlogItems.setHouseId(contract.getHouseId());
//                    //backlogItem.setOrgId(orgId);
//                    backlogItems.setType(BacklogItemTypeEnum.CONTRACT_BILL.getValue());
//                    backlogItems.setTitle("租金/押金账单待缴费");
//                    backlogItems.setContent("缴费描述：合同已生成，请尽快缴费");
//                    backlogItems.setBusinessStatus("待缴费");
//                    backlogItems.setHandleStatus(0);
//                    backlogItems.setOperatorId(userId);
//                    backlogItems.setMatchUserId(appUser !=null ? appUser.getId() : null);
//                    backlogItems.setPhone(appUser !=null ? appUser.getPhone() : null);
//                    backlogItems.setCreateTime(date);
//                    BacklogItem saves = backlogItemRepository.save(backlogItems);
//
//                    BacklogItemContractBill contractBills = new BacklogItemContractBill();
//                    contractBills.setBacklogItemId(saves.getId());
//                    contractBills.setAmount(cose + earnestMoney);
//                    contractBills.setMatchUserId(appUser.getId());
//                    contractBills.setRentBillId(billSave.getId());
//                    contractBills.setDepositBillId(bill2Save.getId());
//                    contractBills.setContractNumber(contractNubmer);
//                    backlogItemContractBillRepository.save(contractBills);
//
//                    //发送租金缴纳短信
//                    smsService.sendTemplateSms(contract.getLeaseeMobile(), smsConfig.getRentbillTemplateCode());
//
//                }
//            }


            return ResultBean.successfulResult(vo);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return ResultBean.failedResultOfException();
        }
    }

    /**
     * 合同续签, 编辑保存
     *
     * @param accessToken
     * @param vo          合同内容
     * @return
     * @author shun
     * @date 2021年6月11日
     */
    @Transactional(rollbackFor = {RuntimeException.class, Exception.class})
    public ResultBean<Object> editContract(String accessToken, ContractVO vo) {
        try {
            TokenRedisVo tokenRedisVo = redisService.findTokenVo(accessToken);
            if (tokenRedisVo == null) {
                return ResultBean.failedResultOfToken();
            }
            //AppUser user = appUserRepository.findByIdAndStatus(tokenRedisVo.getId(), 1);
            AppUser user = appUserService.findByIdAndStatus(tokenRedisVo.getId(), 1, tokenRedisVo.getLoginType());
            if (user == null) {
                return ResultBean.failedResultWithMsg("用户不存在或已禁用");
            }
            // 参数验证
            if (vo == null || vo.getContractNubmer() == null) {
                return ResultBean.failedResultOfParamWithMsg("参数为空");
            }
            /*
             * // 保存前，删除之前草稿状态合同 Contract draft =
             * contractRepository.findByHouseIdAndStatus(vo.getHouseId(), 0); if
             * (draft != null) { String no = draft.getContractNubmer();
             * contractRepository.delete(draft);
             * houseContractFieldRepository.deleteByContractNubmer(no);
             * houseContractAttachmentRepository.deleteByContractNubmer(no); }
             */
            // 合同
            Contract contract = contractRepository.findByContractNubmer(vo.getContractNubmer());
            if (contract == null) {
                return ResultBean.failedResultWithMsg("合同不存在");
            }

            // 合同状态必须是：5已备案履约中、6已到期待续约 10已过期
            if (contract.getStatus() != ContractStatusEnum.WAITING_PERFORMANCE.getValue()
                    && contract.getStatus() != ContractStatusEnum.WAITING_RENEWAL.getValue()
                    && contract.getStatus() != ContractStatusEnum.HAVE_EXPIRED.getValue()) {
                return ResultBean.failedResultWithMsg("合同状态错误, 无法续约");
            }
            // 清空合同签署相关数据
            contract.setContractId(null);
            contract.setDocumentId(null);
            contract.setShortUrl(null);
            contract.setContractDocUrl(null);

            contract.setContractTemplateNumber(vo.getContractTemplateNumber());
            contract.setHouseId(vo.getHouseId());
            contract.setMatchUserId(vo.getMatchUserId());
            contract.setLessorName(vo.getLessorName());
            contract.setLessorMobile(vo.getLessorMobile());
            contract.setLeaseeName(vo.getLeaseeName());
            contract.setLeaseeMobile(vo.getLeaseeMobile());
            contract.setCardNumber(vo.getCardNumber());
            contract.setStartTime(DateUtils.convert(vo.getStartTime(), DateUtils.FORMAT_DATE_8));
            contract.setEntTime(DateUtils.convert(vo.getEntTime(), DateUtils.FORMAT_DATE_8));
            contract.setHousingArea(vo.getHousingArea());
            contract.setRentUnitAmount(ConvertUtils.yuan2fen(vo.getRentUnitAmount()));// 元转分
            contract.setRentAmount(ConvertUtils.yuan2fen(vo.getRentAmount()));// 元转分
            contract.setPayType(vo.getPayType());
            contract.setEarnestMoney(ConvertUtils.yuan2fen(vo.getEarnestMoney()));// 元转分
            contract.setProvinceId(vo.getProvinceId());
            contract.setCityId(vo.getCityId());
            contract.setDistrictId(vo.getDistrictId());
            contract.setStreetId(vo.getStreetId());
            contract.setAddress(vo.getAddress());
            contract.setRoom(vo.getRoom());
            contract.setHall(vo.getHall());
            contract.setToilet(vo.getToilet());
            contract.setStatus(0);// 初稿
            contract.setBusinessType(2);// 续约
            contract.setReminderTime(DateUtils.convert(
                    DateUtils.getAddDaysTime(vo.getEntTime(), DateUtils.FORMAT_DATE_8, -30), DateUtils.FORMAT_DATE_8));// 到期提醒时间，默认提前一个月
            contract.setOperationId(tokenRedisVo.getId());
            contract.setOperationTime(new Date());
            Contract save = contractRepository.save(contract);

            // 设置公租房合同续约状态
            Optional<House> houseOpt = houseRepository.findById(save.getHouseId());
            if (!houseOpt.isPresent()) {
                return ResultBean.failedResultWithMsg("合同数据有误, 无法匹配房屋");
            }
            House house = houseOpt.get();
            // 续签中
            house.setRenewalStatus(2);
            houseRepository.save(house);

            // 自定义字段
            if (!StringUtils.isBlank(vo.getCustomField())) {
                // 清空合同原有的自定义字段
                houseContractFieldRepository.deleteByContractNubmer(save.getContractNubmer());

                List<Map<String, Object>> fields = JsonUtils.str2obj(vo.getCustomField(), List.class);
                for (Map map : fields) {
                    HouseContractField field = new HouseContractField();
                    field.setContractNubmer(save.getContractNubmer());
                    Object fieldId = map.get("fieldId");
                    field.setFieldId(Long.valueOf(String.valueOf(fieldId)));
                    Object fieldName = map.get("fieldName");
                    field.setFieldName(String.valueOf(fieldName));
                    Object name = map.get("name");
                    field.setName(String.valueOf(name));
                    Object value = map.get("value");
                    field.setValue(String.valueOf(value));
                    houseContractFieldRepository.save(field);
                }
            }
            // 合同附件
            if (!StringUtils.isBlank(vo.getContractAttachment())) {
                // 清空合同原附件
                houseContractAttachmentRepository.deleteByContractNubmer(save.getContractNubmer());

                List<Map<String, Object>> attachments = JsonUtils.str2obj(vo.getContractAttachment(), List.class);
                for (Map map : attachments) {
                    HouseContractAttachment attachment = new HouseContractAttachment();
                    attachment.setContractNubmer(save.getContractNubmer());
                    Integer type = Integer.valueOf(String.valueOf(map.get("type")));
                    attachment.setType(type);
                    if (type == 1) {
                        Object attachmentId = map.get("attachmentId");
                        attachment.setAttachmentId(Long.valueOf(String.valueOf(attachmentId)));
                    }
                    Object name = map.get("name");
                    attachment.setName(String.valueOf(name));
                    Object unit = map.get("unit");
                    attachment.setUnit(String.valueOf(unit));
                    Object currentSituation = map.get("currentSituation");
                    attachment.setCurrentSituation(String.valueOf(currentSituation));
                    Object unitPrice = map.get("unitPrice");
                    attachment.setUnitPrice(String.valueOf(unitPrice));
                    attachment.setOperatorId(tokenRedisVo.getId());
                    attachment.setLastUpdateTime(new Date());
                    houseContractAttachmentRepository.save(attachment);
                }
            }

            return ResultBean.successfulResult(save.getContractNubmer());
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return ResultBean.failedResultOfException();
        }
    }

    /**
     * 合同明细
     *
     * @param contract
     * @return
     * @author shun
     * @date 2021年6月15日
     */
    public ContractContentDetailVO getContractDetail(Contract contract) {
        try {
            String contractTemplateNumber = contract.getContractTemplateNumber();
            ContractTemplate contractTemplate = contractTemplateRepository
                    .findByContractTemplateNumber(contractTemplateNumber);
            if (contractTemplate == null) {
                log.error("合同模板不存在, contractNumber={}", contract.getContractNubmer());
                return null;
            }
            ContractContentDetailVO vo = new ContractContentDetailVO();
            // 合同条款
            vo.setContractTerms(contractTemplate.getContent());
            // 合同标题
            //vo.setTitle(contractTemplate.getName());

            // 合同附件
            String sql = "SELECT a.name,a.unit,a.current_situation AS currentSituation,a.unit_price AS unitPrice\n"
                    + "FROM `saas_house_contract_attachment` a WHERE a.contract_nubmer = ?";
            List<ContractAttachmentVO> list = jdbcTemplate.query(sql.toString(),
                    BeanPropertyRowMapper.newInstance(ContractAttachmentVO.class), contract.getContractNubmer());
            vo.setContractAttachmentVO(list);

            // 合同字段
            ResultBean<Object> obj = findContractField(contract.getContractNubmer());
            vo.setFieldList((List<Map<String, Object>>) obj.getResultData());

            return vo;
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return null;
        }
    }
}
